package test;

import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

import shake.annotation.ApplicationScoepd;
import shake.annotation.Component;
import shake.annotation.Observer;
import shake.annotation.Unwrap;
import shake.event.JSFPhaseEvent;
import shake.event.ShakeEvent;

import com.google.inject.Inject;
import com.google.inject.servlet.RequestScoped;

@RequestScoped
@Component
public class PersistenceFactoryImpl {

	@Inject
	public PersistenceFactoryImpl(EntityManagerFactory factory) {
		this.manager = factory.createEntityManager();
	}

	EntityManager manager;

	@Unwrap
	public EntityManager get() {
		return manager;
	}

	@Unwrap
	EntityTransaction transaction() {
		return manager.getTransaction();
	}

	@Observer(value = ShakeEvent.DESTROY.class)
	public void destory(PersistenceFactoryImpl imple) {
		if (manager.isOpen()) {
			manager.close();
		}
	}

	@Observer(value = JSFPhaseEvent.BEFORE.class)
	public void before(PhaseEvent phase) {
		EntityTransaction transaction = manager.getTransaction();
		if (!transaction.isActive()) {
			transaction.begin();
		}
	}

	@Observer(value = JSFPhaseEvent.AFTER.class)
	public void after(PhaseEvent phase) {
		EntityTransaction transaction = manager.getTransaction();

		if (phase.getPhaseId().equals(PhaseId.INVOKE_APPLICATION)) {
			if (transaction.isActive()) {
				transaction.commit();
			}
			return;
		}
		if (phase.getFacesContext().getResponseComplete()) {
			if (transaction.isActive()) {
				transaction.commit();
			}
		}

	}

	@ApplicationScoepd
	@Component
	public static class Factory {
		EntityManagerFactory factory;

		@Inject
		public Factory() {
			factory = Persistence.createEntityManagerFactory("test");

		}

		@Unwrap
		public EntityManagerFactory factory() {
			return factory;
		}

		@Observer(value = ShakeEvent.DESTROY.class)
		public void destory(Factory imple) {
			factory.close();
		}
	}

}
